
`include "defines.v"

module rvcpu (
    input               clock,
    input               reset,


);
    

    // Pc
    // Pc -> If, Mux_alu_ia, Mux_offset
    wire [`BUS_WIDTH] inst_addr;

    // Inst_rom
    // Inst_rom -> Id, Ie
    wire [31 :     0] inst;
    
    // Ctr_cpu
    // Ctr_cpu -> Ie
    wire [2 :      0] ext_op;
    // Ctr_cpu -> Reg
    wire              reg_wen;
    // Ctr_cpu -> Alu
    wire [3 :      0] alu_ctr;
    // Ctr_cpu -> Ctr_mem, Data_mem
    wire              mem_ren;
    wire              mem_wen;
    // Ctr_cpu -> Mux_alu_ia
    wire              alu_asrc;
    // Ctr_cpu -> Mux_alu_ib
    wire [1 :      0] alu_bsrc;
    // Ctr_cpu -> Mux_w_data
    wire              mem2reg;
    // Ctr_cpu -> Mux_offset
    wire [1 :      0] pc_sel;
    // Ctr_cpu -> Ctr_mem, Mux_width
    wire [2 :      0] width_sel;

    // Ctr_mem
    // Ctr_mem -> Data_mem
    wire [`BUS_WIDTH] mem_wdata;
    wire [`BUS_WIDTH] mem_wmask;
    // Ctr_mem -> Mux_w_data
    wire [`BUS_WIDTH] data_out;
    
    // Id
    // Id -> Reg_file
    wire [4 :      0] rs1;
    wire [4 :      0] rs2;
    wire [4 :      0] rd;
    // Id -> Ctr_cpu
    wire [4 :      0] op;
    wire [2 :      0] f3;
    wire              f7;

    // Reg_file
    // Reg_file -> Mux_alu_ia, Mux_offset
    wire [`BUS_WIDTH] r_data1;
    // Reg_file -> Ctr_mem, Mux_alu_ib
    wire [`BUS_WIDTH] r_data2;
    // Reg_file -> Difftest
    wire [`BUS_WIDTH] regs_o[31 : 0];
    
    // Ie
    // Ie -> Mux_alu_ib, Mux_offset
    wire [`BUS_WIDTH] imm;

    // Mux_alu_ia
    // Mux_alu_ia -> Alu
    wire [`BUS_WIDTH] alu_ia;

    // Mux_alu_ib
    // Mux_alu_ib -> Alu
    wire [`BUS_WIDTH] alu_ib;

    // Alu
    // Alu -> Ctr_cpu, Ctr_mem, Mux_w_data, Data_mem
    wire [`BUS_WIDTH] result;
    // Alu -> Ctr_cpu
    wire              zero;

    // Data_mem
    // Data_mem -> Mux_w_data
    wire [`BUS_WIDTH] mem_rdata;

    // Mux_w_data
    // Mux_w_data -> Ctr_mem
    wire [`BUS_WIDTH] mux_width_i;

    // Mux_width
    // Mux_width -> Reg_file
    wire [`BUS_WIDTH] w_data;

    // Mux_offset
    // Mux_offset -> Pc
    wire [`BUS_WIDTH] offset;


    pc Pc (
        .clk            (clock),
        .rst            (reset),

        .offset         (offset),
        .inst_addr      (inst_addr)
    );

    inst_rom Inst_rom (
        .clk            (clock),
        .rst            (reset),
        
        .inst_addr      (inst_addr),
        .inst           (inst)
    );
    
    ctr_cpu Ctr_cpu (
        .rst            (reset),
        
        .op             (op),
        .f3             (f3),
        .f7             (f7),

        .zero           (zero),
        .result         (result),

        .ext_op         (ext_op),
        .reg_wen        (reg_wen),
        .alu_ctr        (alu_ctr),
        .mem_ren        (mem_ren),
        .mem_wen        (mem_wen),
        .alu_asrc       (alu_asrc),
        .alu_bsrc       (alu_bsrc),
        .mem2reg        (mem2reg),
        .pc_sel         (pc_sel),
        .width_sel      (width_sel)
    );

    ctr_mem Ctr_mem (
        .rst            (reset),

        .mem_ren        (mem_ren),
        .mem_wen        (mem_wen),
        .addr           (result),
        .data_in        (r_data2),
        .width_sel      (width_sel),
        .data_out       (data_out),

        .mem_rdata      (mem_rdata),
        .mem_wdata      (mem_wdata),
        .mem_wmask      (mem_wmask)
    );
    
    id Id (
        .rst            (reset),
        
        .inst           (inst),

        .op             (op),
        .f3             (f3),
        .f7             (f7),
        .rs1            (rs1),
        .rs2            (rs2),
        .rd             (rd)
    );

    reg_file Reg_file (
        .clk            (clock),
        .rst            (reset), 

        .w_addr         (rd),
        .w_data         (w_data),
        .reg_wen        (reg_wen),

        .r_addr1        (rs1),
        .r_data1        (r_data1),

        .r_addr2        (rs2),
        .r_data2        (r_data2),

        .regs_o         (regs_o)
    );

    ie Ie (
        .rst            (reset),
        
        .inst           (inst),
        .ext_op         (ext_op),

        .imm            (imm)
    );

    mux_alu_ia Mux_alu_ia (
        .rst            (reset),
        
        .inst_addr      (inst_addr),
        .r_data1        (r_data1),
        .alu_asrc       (alu_asrc),

        .alu_ia         (alu_ia)
    );

    mux_alu_ib Mux_alu_ib (
        .rst            (reset),
        
        .r_data2        (r_data2),
        .imm            (imm),
        .alu_bsrc       (alu_bsrc),

        .alu_ib         (alu_ib)
    );

    alu Alu (
        .rst            (reset),
        
        .alu_ia         (alu_ia),
        .alu_ib         (alu_ib),
        .alu_ctr        (alu_ctr),

        .result         (result),
        .zero           (zero)
    );

    data_mem Data_mem (
        .clk            (clock),
        .rst            (reset), 
        
        .addr           (result),
        .mem_wdata      (mem_wdata),
        .mem_ren        (mem_ren),
        .mem_wmask      (mem_wmask),
        .mem_wen        (mem_wen),

        .mem_rdata      (mem_rdata)
    );

    mux_w_data Mux_w_data (
        .rst            (reset),
        
        .result         (result),
        .data_out       (data_out),
        .mem2reg        (mem2reg),

        .w_data         (mux_width_i)
    );

    mux_width Mux_width (
        .rst            (reset),
        
        .mux_width_i    (mux_width_i),
        .width_sel      (width_sel),

        .mux_width_o    (w_data)
    );

    mux_offset Mux_offset (
        .rst            (reset),
        
        .imm            (imm),
        .r_data1        (r_data1),
        .inst_addr      (inst_addr),
        .pc_sel         (pc_sel),

        .offset         (offset)
    );

    
endmodule
